.code16
.text
    mov %cs, %ax
    mov %ax, %ds
    mov %ax, %es
    
    # display welcome info
    call displayString 
    
    # read asm code from floppy to memory
    # after call return
    # all asm code in memory
    # start from 0x7c00
    call loadsetup
    
    # collect system info
    # those info start from 0xcfeff to 0xcffff
    # total 256B
    # 1. [0x6c00:0x6c01] - 0xcfget memory size = total size(KB) - 1(M)
    call getmemsize
    
    # prepare move to protect mode
    # 1. disable interrupt
    cli
    
    # 2. setup gdt
    call setupgdt
    
    # 3. setup idt
    call setupidt
    
    # 4. setup page table
    call setuppage
    
    # 5. enable A20
    call enablea20
    
    # 6. modify bios interrupt
    call modifyinter
    
    # 7. load idt and gd
    lidt idt_register
    lgdt gdt_register
    
    # now finish prepare
    # enter protect mode
    # load idt and gdt
    # load cr3 to page directory
    # set PE and PG flag in cr0
    xorl %eax, %eax
    movl %eax, %cr3
    movl %cr0, %eax
    orl $0x80000001, %eax
    movl %eax, %cr0
    ljmp $0x8, $protect_start
    
modifyinter:
    # reference linux0.11
    mov $0x11, %al
    outb %al, $0x20
    .word 0x00eb, 0x00eb
    outb %al, $0xa0
    .word 0x00eb, 0x00eb
    mov $0x20, %al
    outb %al, $0x21
    .word 0x00eb, 0x00eb
    mov $0x28, %al
    outb %al, $0xa1
    .word 0x00eb, 0x00eb
    mov $0x04, %al
    outb %al, $0x21
    .word 0x00eb, 0x00eb
    mov $0x02, %al
    outb %al, $0xa1
    .word 0x00eb, 0x00eb
    mov $0x01, %al
    outb %al, $0x21
    .word 0x00eb, 0x00eb
    outb %al, $0xa1
    .word 0x00eb, 0x00eb
    mov $0xff, %al
    outb %al, $0x21
    .word 0x00eb, 0x00eb
    outb %al, $0xa1
    ret

enablea20:
    # reference writeos-1.0-2-weekly
    inb $0x92, %al
    orb $0b00000010, %al
    outb %al, $0x92
    ret

setuppage:
    # clear memory of pdt and pet
    mov $256*5, %ecx
    xorl %eax, %eax
    xor %edi, %edi
    cld;rep;stosl
    # set page directory entry
    movl $0x0, %ebx
    movl $0x1007, %eax
    movl %eax, (%ebx)
    movl $0x2007, %eax
    movl %eax, 4(%ebx)
    movl $0x3007, %eax
    movl %eax, 8(%ebx)
    movl $0x4007, %eax
    movl %eax, 12(%ebx)
    # set page entry table
    movl $0x00001000, %ebx
    movl $0x00000007, %eax
    movl $0x0fff, %ecx
loop:
    movl %eax, (%ebx)
    add $0x4, %ebx
    add $0x1000, %eax
    sub $0x1, %cx
    jnc loop
    ret

setupidt:
    # set 256 entrys(NULL)
    mov $0x0200, %cx
    xor %ax, %ax
    mov $0x5800, %di
    cld;rep;stosl
    ret
    

setupgdt:
    # set first entry(NULL)
    mov $0x2, %cx
    xor %ax, %ax
    mov $0x5000, %di
    cld;rep;stosl
    # set second entry(kernel code segment)
    movl $0x00000fff, %eax
    movl $0x00005008, %ebx
    movl %eax, (%ebx)
    movl $0x00c09a00, %eax
    movl $0x0000500c, %ebx
    movl %eax, (%ebx)
    # set third entry(kernel data segment)
    movl $0x00000fff, %eax
    movl $0x00005010, %ebx
    movl %eax, (%ebx)
    movl $0x00c09200, %eax
    movl $0x00005014, %ebx
    movl %eax, (%ebx)
    # set rest 252 entrys(NULL)
    mov $0x1f8, %ecx
    xorl %eax, %eax
    mov $0x5018, %edi
    cld;rep;stosl
    ret

getmemsize:
    # get memory size
    # INT 0x15
    # ah = 0x88
    # ax = size (return value)
    mov $0x8800, %ax
    int $0x15
    mov $0x6c00, %bx
    mov %ax, (%bx)
    ret
    
loadsetup:
    # load data from floppy to memory
    # INT 0x13
    # ah = 0x02 ---- from floppy to memory
    # al = 0x1 ---- number of sectors need to read
    # ch = 0x0 ---- number of track
    # cl = 0x2 ---- number of start sector
    # dh = 0x0 ---- number of head
    # dl = 0x0 ---- number of drive
    # es:bx = 0x7e00 ---- memory address
    mov $0x0204, %ax
    mov $0x0002, %cx
    mov $0x0000, %dx
    mov $0x7e00, %bx
    int $0x13
    jc loadsetup
    ret

displayString:
    mov $bootMessage, %ax
    mov %ax, %bp
    mov $16, %cx
    mov $0x1301, %ax
    mov $0xc, %bx
    mov $0, %dl
    int $0x10
    ret
    
idt_register:
    .word 0x0800
    .word 0x5800, 0x0
    
gdt_register:
    .word 0x0800
    .word 0x5000, 0x0

bootMessage:.ascii "hello, os world!"

.code32
protect_start:
    #    reload each segment
    #    set stack point
    #    push _main entry
    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %ss
    mov %ax, %fs
    mov %ax, %gs
    movl $0x0009ffff, %eax
    movl %eax, %esp
    pushl $0x0  # envp
    pushl $0x0  # argv
    pushl $0x0  # argc
    pushl $deadloop  # return address
    pushl $main
    ret
deadloop:
    jmp deadloop

.org 510
.byte 0x55
.byte 0xaa

